#include <cstdio>
#include "httplib.h"
#include "data.hpp"
#include "daemonize.hpp"

#define WWWROOT "./www"
#define VIDEO_ROOT "/video/"
#define IMAGE_ROOT "/image/"

namespace aod
{
    TableVideo *tb_video = nullptr;
    TableUser *tb_user = nullptr; // 新增：用户数据表管理类指针

    class Server
    {
    private:
        // static修饰类成员函数是为了隐藏this指针，满足httplib回调函数的参数需求
        static void Insert(const httplib::Request &req, httplib::Response &rsp)
        {
            if (req.has_file("name") == false ||
                req.has_file("info") == false ||
                req.has_file("image") == false)
            {
                rsp.status = 400;
                rsp.body = R"({"result":false, "reason":"上传的数据信息错误"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            // 1.请求数据的获取
            httplib::MultipartFormData name = req.get_file_value("name");   // 视频名称
            httplib::MultipartFormData info = req.get_file_value("info");   // 视频简介
            httplib::MultipartFormData video = req.get_file_value("video"); // 视频文件
            httplib::MultipartFormData image = req.get_file_value("image"); // 图片文件

            /* MultipartFormData 内部有四个成员
            struct MultipartFormData {
                std::string name;         // 字段名
                std::string content;      // 文件内容数据
                std::string filename;     // 文件名称
                std::string content_type; // 正文类型（不用关心）
            }; */

            std::string video_name = name.content;
            std::string video_info = info.content;

            // ./www/iamge/变形金刚a.jpg
            std::string root = WWWROOT;
            std::string video_path = root + VIDEO_ROOT + video_name + video.filename;
            std::string image_path = root + IMAGE_ROOT + video_name + image.filename;

            // 2.视频和封面图片的存储，并判断文件是否存储失败
            if (FileUtil(video_path).SetContent(video.content) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"视频文件存储失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            if (FileUtil(image_path).SetContent(image.content) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"图片文件存储失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            // 3.数据库数据信息的新增
            Json::Value video_json;
            video_json["name"] = video_name;
            video_json["info"] = video_info;
            video_json["video"] = VIDEO_ROOT + video_name + video.filename; // /video/变形金刚robot.mp4
            video_json["image"] = IMAGE_ROOT + video_name + image.filename; // /image/变形金刚image.jpg

            // 判断数据库是否插入成功
            if (tb_video->Insert(video_json) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"数据库新增数据失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            rsp.set_redirect("/index.html", 303);
        }

        static void Delete(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1.获取要删除的视频ID
            int video_id = std::stoi(req.matches[1]);

            // 2.删除视频以及图片文件
            Json::Value video;
            if (tb_video->SelectOne(video_id, &video) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"不存在视频信息"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            std::string root = WWWROOT;
            std::string video_path = root + video["video"].asString();
            std::string image_path = root + video["image"].asString();
            remove(video_path.c_str());
            remove(image_path.c_str());

            // 3.删除数据库信息
            if (tb_video->Delete(video_id) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"删除数据库信息失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
        }

        static void Update(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1.获取要修改的视频 (1)视频ID (2)修改后的信息
            int video_id = std::stoi(req.matches[1]);

            Json::Value video;
            if (JsonUtil::UnSerialize(req.body, &video) == false)
            {
                rsp.status = 400;
                rsp.body = R"({"result":false, "reason":"新的视频格式解析失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            // 2.修改数据库数据
            if (tb_video->Update(video_id, video) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"修改数据库信息失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
        }

        static void SelectOne(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1.获取视频信息ID
            int video_id = std::stoi(req.matches[1]);

            // 2.在数据库中查询指定视频信息
            Json::Value video;
            if (tb_video->SelectOne(video_id, &video) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"查询数据库指定视频信息失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            // 3.组织响应正文--json格式的字符串
            JsonUtil::Serialize(video, &rsp.body);

            // 决定了浏览器如何去处理正文--浏览器收到响应之后按照json格式解析的
            rsp.set_header("Content-Type", "application/json");
        }

        static void SelectALL(const httplib::Request &req, httplib::Response &rsp)
        {
            // /video  or /video?search="关键字"

            std::string search_key;
            bool select_flag = true; // 默认所有查询
            if (req.has_param("search") == true)
            {
                select_flag = false; // 模糊匹配
                search_key = req.get_param_value("search");
            }

            Json::Value videos;
            if (select_flag == true)
            {
                if (tb_video->SelectAll(&videos) == false)
                {
                    rsp.status = 500;
                    rsp.body = R"({"result":false, "reason":"查询数据库所有视频信息失败"})";
                    rsp.set_header("Content-Type", "application/json");
                    return;
                }
            }
            else
            {
                if (tb_video->SelectLike(search_key, &videos) == false)
                {
                    // std::cerr << "search_key: " << search_key << std::endl;
                    rsp.status = 500;
                    rsp.body = R"({"result":false, "reason":"查询数据库匹配视频信息失败"})";
                    rsp.set_header("Content-Type", "application/json");
                    return;
                }
            }

            // 组织响应正文--json格式的字符串
            JsonUtil::Serialize(videos, &rsp.body);

            // 决定了浏览器如何去处理正文--浏览器收到响应之后按照json格式解析的
            rsp.set_header("Content-Type", "application/json");
        }

        // 新增：注册处理函数
        static void Register(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1. 请求数据的解析
            Json::Value user;
            Json::Reader reader;
            if (!reader.parse(req.body, user))
            {
                rsp.status = 400;
                rsp.body = R"({"result":false, "reason":"请求数据解析失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            // 2. 检查必要的用户信息字段
            // 2.1 检查用户名是否为空
            if (user["username"].isNull() || user["username"].asString().empty())
            {
                rsp.status = 400;
                rsp.body = R"({"result":false, "reason":"用户名不能为空"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            // 2.2 检查密码是否为空
            if (user["password"].isNull() || user["password"].asString().empty())
            {
                rsp.status = 400;
                rsp.body = R"({"result":false, "reason":"用户密码不能为空"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            // 3. 数据库数据信息的新增
            if (tb_user->Insert(user) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"用户注册失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            // 4. 注册成功处理
            rsp.status = 200;
            rsp.body = R"({"result":true, "reason":"用户注册成功"})";
            rsp.set_header("Content-Type", "application/json");
        }

        // 新增：登录处理函数
        static void Login(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1. 请求数据的解析
            Json::Value user;
            Json::Reader reader;
            if (!reader.parse(req.body, user))
            {
                rsp.status = 400;
                rsp.body = R"({"result":false, "reason":"请求数据解析失败"})";
                rsp.set_header("Content-Type", "application/json");
                std::cerr << "Login request data parse failed." << std::endl;
                return;
            }

            std::string user_name = user["username"].asString();
            std::string user_password = user["password"].asString();

            // 2. 检查必要的用户信息字段
            // 2.1 检查用户名是否为空
            if (user_name.empty())
            {
                rsp.status = 400;
                rsp.body = R"({"result":false, "reason":"用户名不能为空"})";
                rsp.set_header("Content-Type", "application/json");
                std::cerr << "Username is empty in login request." << std::endl;
                return;
            }
            // 2.2 检查密码是否为空
            if (user_password.empty())
            {
                rsp.status = 400;
                rsp.body = R"({"result":false, "reason":"用户密码不能为空"})";
                rsp.set_header("Content-Type", "application/json");
                std::cerr << "Password is empty in login request." << std::endl;
                return;
            }

            // 3. 判断用户名是否存在
            Json::Value stored_user;
            if (tb_user->SelectOne(user_name, &stored_user) == false)
            {
                rsp.status = 200; // 修改为 200 状态码，统一由 JSON 数据中的 result 判断结果
                rsp.body = R"({"result":false, "reason":"查无此用户"})";
                rsp.set_header("Content-Type", "application/json");
                std::cerr << "Username " << user_name << " not found." << std::endl;
                return;
            }

            // 4. 验证密码
            std::string stored_password = stored_user["password"].asString();
            if (user_password != stored_password)
            {
                rsp.status = 200; // 修改为 200 状态码，统一由 JSON 数据中的 result 判断结果
                rsp.body = R"({"result":false, "reason":"密码错误"})";
                rsp.set_header("Content-Type", "application/json");
                std::cerr << "Password incorrect for username " << user_name << std::endl;
                return;
            }

            // 5. 登录成功处理
            rsp.status = 200;
            rsp.body = R"({"result":true, "reason":"用户登录成功"})";
            rsp.set_header("Content-Type", "application/json");
            std::cout << "User " << user_name << " logged in successfully." << std::endl;
        }

        // 新增：点赞处理函数
        static void LikeVideo(const httplib::Request &req, httplib::Response &rsp)
        {
            int video_id = std::stoi(req.matches[1]);
            if (tb_video->UpdateLikes(video_id) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"更新点赞数量失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            rsp.status = 200;
            rsp.body = R"({"result":true, "reason":"点赞成功"})";
            rsp.set_header("Content-Type", "application/json");
        }

        // 新增：收藏处理函数
        static void CollectVideo(const httplib::Request &req, httplib::Response &rsp)
        {
            int video_id = std::stoi(req.matches[1]);
            if (tb_video->UpdateCollects(video_id) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"更新收藏数量失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            rsp.status = 200;
            rsp.body = R"({"result":true, "reason":"收藏成功"})";
            rsp.set_header("Content-Type", "application/json");
        }

        // 新增：获取视频信息函数
        static void GetVideoDetails(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1.获取视频信息ID
            int video_id = std::stoi(req.matches[1]);

            // 2.在数据库中查询指定视频信息
            Json::Value video;
            if (tb_video->SelectOne(video_id, &video) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"查询数据库指定视频信息失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            // 3.组织响应正文--json格式的字符串
            JsonUtil::Serialize(video, &rsp.body);

            // 决定了浏览器如何去处理正文--浏览器收到响应之后按照json格式解析的
            rsp.set_header("Content-Type", "application/json");
        }

        // 新增：获取用户信息函数
        static void GetUserInfo(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1. 获取用户名
            std::string user_name = req.get_param_value("username");

            // 2. 检查用户名是否为空
            if (user_name.empty())
            {
                rsp.status = 400;
                rsp.body = R"({"result":false, "reason":"用户名不能为空"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            // 3. 在数据库中查询指定用户信息
            Json::Value user;
            if (tb_user->SelectOne(user_name, &user) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"查询数据库指定用户信息失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            // 4. 组织响应正文 -- json格式的字符串
            JsonUtil::Serialize(user, &rsp.body);

            // 决定了浏览器如何去处理正文 -- 浏览器收到响应之后按照json格式解析的
            rsp.set_header("Content-Type", "application/json");
        }

    public:
        Server(int port)
            : _port(port)
        {
        }

        bool RunModule()
        {
            // 变成守护进程
            // daemonize();

            // 1.初始化操作 -- 初始化数据管理模块，创建指定的目录
            tb_video = new TableVideo();
            tb_user = new TableUser();
            FileUtil(WWWROOT).CreateDirectory();

            std::string root = WWWROOT;
            std::string video_real_path = root + VIDEO_ROOT; // ./www/video/
            FileUtil(video_real_path).CreateDirectory();

            std::string image_real_path = root + IMAGE_ROOT; // ./www/image/
            FileUtil(image_real_path).CreateDirectory();

            // 2.搭建http服务器，开始运行

            // 2.1设置静态资源根目录
            _srv.set_mount_point("/", WWWROOT);

            // 2.2添加请求-处理函数映射关系 - 回调函数是需要我们自己完成的
            // 两个参数，（请求信息，需要填充的响应信息）返回值是空
            _srv.Post("/video", Insert);
            _srv.Delete("/video/(\\d+)", Delete);
            _srv.Put("/video/(\\d+)", Update);
            _srv.Get("/video/(\\d+)", SelectOne);
            _srv.Get("/video", SelectALL);

            // 新增：注册路由映射和登录路由映射
            _srv.Post("/register", Register);
            _srv.Post("/login", Login);

            // 新增：视频点赞
            _srv.Post("/video/(\\d+)/like", LikeVideo);

            // 新增：视频收藏
            _srv.Post("/video/(\\d+)/collect", CollectVideo);

            // 新增：获取视频详情接口
            _srv.Get("/video/(\\d+)", GetVideoDetails);

            _srv.Get("/video", GetUserInfo);

            // 2.3启动服务器
            _srv.listen("0.0.0.0", _port);

            return true;
        }

    private:
        int _port;
        httplib::Server _srv;
    };
}
